package top.bulk.dbcrypto.util;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotationUtils;
import top.bulk.dbcrypto.annotion.Crypto;
import top.bulk.dbcrypto.annotion.CryptoField;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.function.Function;

/**
 * 注解工具类
 *
 * @author 散装java
 * @date 2024-08-01
 */
@Slf4j
public class AnnUtil {

    /**
     * 判断类上是否有 Crypto 注解
     */
    public static boolean hasCrypto(Class<?> clz) {
        return AnnotationUtils.isCandidateClass(clz, Crypto.class);
    }

    /**
     * 不管加密还是解密，都会对左右字段遍历，然后替换原来的值。
     *
     * @param object   处理对象
     * @param function 加密 或者解密 方法
     */
    @SneakyThrows
    public static void doFiled(Object object, Function<String, String> function) {
        if (Objects.isNull(object) || !hasCrypto(object.getClass())) {
            return;
        }
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        // 遍历所有字段，判断是否是String类型，以及是否包含Crypto注解，如果满足则进行加密，且替换原始值
        for (Field field : fields) {
            Type fieldClazz = field.getGenericType();
            if (!(fieldClazz instanceof Class) || !String.class.isAssignableFrom((Class<?>) fieldClazz)) {
                continue;
            }
            if (AnnotationUtil.hasAnnotation(field, CryptoField.class)) {
                field.setAccessible(true);
                Object originVal = field.get(object);
                if (null == originVal || StrUtil.isBlank(originVal.toString())) {
                    continue;
                }
                String encryptedStr = function.apply(originVal.toString());
                field.set(object, encryptedStr);
            }
        }
    }
}
